home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 June / Chip_2002-06_cd1.bin / zkuste / delphi / kolekce / d6 / rxlibsetup.exe / {app} / units / Animate.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2002-02-19  |  19.6 KB  |  813 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 2001,2002 SGB Software          }
  6. {         Copyright (c) 1997, 1998 Fedor Koshevnikov,   }
  7. {                        Igor Pavluk and Serge Korolev  }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11. unit Animate;
  12.  
  13. interface
  14.  
  15. {$I RX.INC}
  16.  
  17. uses Messages, {$IFDEF WIN32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF}
  18.   SysUtils, Classes, Graphics, Controls, Forms, StdCtrls, Menus, RxTimer;
  19.  
  20. type
  21.  
  22. { TRxImageControl }
  23.  
  24.   TRxImageControl = class(TGraphicControl)
  25.   private
  26.     FDrawing: Boolean;
  27.     FPaintBuffered: Boolean;
  28. {$IFDEF RX_D3}
  29.     FLock: TRTLCriticalSection;
  30. {$ENDIF}
  31.     procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  32.   protected
  33.     FGraphic: TGraphic;
  34.     function DoPaletteChange: Boolean;
  35. {$IFNDEF RX_D4}
  36.     procedure AdjustSize; virtual; abstract;
  37. {$ENDIF}
  38.     procedure DoPaintImage; virtual; abstract;
  39.     procedure DoPaintControl;
  40.     procedure PaintDesignRect;
  41.     procedure PaintImage;
  42.     procedure PictureChanged;
  43.     procedure Lock;
  44.     procedure Unlock;
  45.   public
  46.     constructor Create(AOwner: TComponent); override;
  47.     destructor Destroy; override;
  48.   end;
  49.  
  50. { TAnimatedImage }
  51.  
  52.   TGlyphOrientation = (goHorizontal, goVertical);
  53.  
  54.   TAnimatedImage = class(TRxImageControl)
  55.   private
  56.     FActive: Boolean;
  57.     FGlyph: TBitmap;
  58.     FImageWidth: Integer;
  59.     FImageHeight: Integer;
  60.     FInactiveGlyph: Integer;
  61.     FOrientation: TGlyphOrientation;
  62.     FTimer: TRxTimer;
  63.     FNumGlyphs: Integer;
  64.     FGlyphNum: Integer;
  65.     FCenter: Boolean;
  66.     FStretch: Boolean;
  67.     FTransparentColor: TColor;
  68.     FOpaque: Boolean;
  69.     FTimerRepaint: Boolean;
  70.     FOnFrameChanged: TNotifyEvent;
  71.     FOnStart: TNotifyEvent;
  72.     FOnStop: TNotifyEvent;
  73. {$IFDEF RX_D3}
  74.     FAsyncDrawing: Boolean;
  75. {$ENDIF}
  76. {$IFNDEF RX_D4}
  77.     FAutoSize: Boolean;
  78.     procedure SetAutoSize(Value: Boolean);
  79. {$ENDIF}
  80.     procedure DefineBitmapSize;
  81.     procedure ResetImageBounds;
  82.     function GetInterval: Cardinal;
  83.     procedure SetInterval(Value: Cardinal);
  84.     procedure SetActive(Value: Boolean);
  85. {$IFDEF RX_D3}
  86.     procedure SetAsyncDrawing(Value: Boolean);
  87. {$ENDIF}
  88.     procedure SetCenter(Value: Boolean);
  89.     procedure SetOrientation(Value: TGlyphOrientation);
  90.     procedure SetGlyph(Value: TBitmap);
  91.     procedure SetGlyphNum(Value: Integer);
  92.     procedure SetInactiveGlyph(Value: Integer);
  93.     procedure SetNumGlyphs(Value: Integer);
  94.     procedure SetStretch(Value: Boolean);
  95.     procedure SetTransparentColor(Value: TColor);
  96.     procedure SetOpaque(Value: Boolean);
  97.     procedure ImageChanged(Sender: TObject);
  98.     procedure UpdateInactive;
  99.     procedure TimerExpired(Sender: TObject);
  100.     function TransparentStored: Boolean;
  101.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  102.   protected
  103. {$IFDEF RX_D4}
  104.     function CanAutoSize(var NewWidth, NewHeight: Integer): Boolean; override;
  105. {$ENDIF}
  106.     function GetPalette: HPALETTE; override;
  107.     procedure AdjustSize; override;
  108.     procedure Loaded; override;
  109.     procedure Paint; override;
  110.     procedure DoPaintImage; override;
  111.     procedure FrameChanged; dynamic;
  112.     procedure Start; dynamic;
  113.     procedure Stop; dynamic;
  114.   public
  115.     constructor Create(AOwner: TComponent); override;
  116.     destructor Destroy; override;
  117.   published
  118.     property Align;
  119. {$IFDEF RX_D4}
  120.     property Anchors;
  121.     property Constraints;
  122.     property DragKind;
  123.     property AutoSize default True;
  124. {$ELSE}
  125.     property AutoSize: Boolean read FAutoSize write SetAutoSize default True;
  126. {$ENDIF}
  127. {$IFDEF RX_D3}
  128.     property AsyncDrawing: Boolean read FAsyncDrawing write SetAsyncDrawing default False;
  129. {$ENDIF}
  130.     property Active: Boolean read FActive write SetActive default False;
  131.     property Center: Boolean read FCenter write SetCenter default False;
  132.     property Orientation: TGlyphOrientation read FOrientation write SetOrientation
  133.       default goHorizontal;
  134.     property Glyph: TBitmap read FGlyph write SetGlyph;
  135.     property GlyphNum: Integer read FGlyphNum write SetGlyphNum default 0;
  136.     property Interval: Cardinal read GetInterval write SetInterval default 100;
  137.     property NumGlyphs: Integer read FNumGlyphs write SetNumGlyphs default 1;
  138.     property InactiveGlyph: Integer read FInactiveGlyph write SetInactiveGlyph default -1;
  139.     property TransparentColor: TColor read FTransparentColor write SetTransparentColor
  140.       stored TransparentStored;
  141.     property Opaque: Boolean read FOpaque write SetOpaque default False;
  142.     property Color;
  143.     property Cursor;
  144.     property DragCursor;
  145.     property DragMode;
  146.     property ParentColor default True;
  147.     property ParentShowHint;
  148.     property PopupMenu;
  149.     property ShowHint;
  150.     property Stretch: Boolean read FStretch write SetStretch default True;
  151.     property Visible;
  152.     property OnClick;
  153.     property OnDblClick;
  154.     property OnMouseMove;
  155.     property OnMouseDown;
  156.     property OnMouseUp;
  157.     property OnDragOver;
  158.     property OnDragDrop;
  159.     property OnEndDrag;
  160. {$IFDEF WIN32}
  161.     property OnStartDrag;
  162. {$ENDIF}
  163. {$IFDEF RX_D4}
  164.     property OnEndDock;
  165.     property OnStartDock;
  166. {$ENDIF}
  167. {$IFDEF RX_D5}
  168.     property OnContextPopup;
  169. {$ENDIF}
  170.     property OnFrameChanged: TNotifyEvent read FOnFrameChanged write FOnFrameChanged;
  171.     property OnStart: TNotifyEvent read FOnStart write FOnStart;
  172.     property OnStop: TNotifyEvent read FOnStop write FOnStop;
  173.   end;
  174.  
  175. {$IFDEF RX_D3}
  176. procedure HookBitmap;
  177. {$ENDIF}
  178.  
  179. implementation
  180.  
  181. uses RxConst, {$IFDEF RX_D3} RxHook, {$ENDIF} VCLUtils;
  182.  
  183. {$IFDEF RX_D3}
  184.  
  185. { THackBitmap }
  186.  
  187. type
  188.   THackBitmap = class(TBitmap)
  189.   protected
  190.     procedure Draw(ACanvas: TCanvas; const Rect: TRect); override;
  191.   end;
  192.  
  193. procedure THackBitmap.Draw(ACanvas: TCanvas; const Rect: TRect);
  194. begin
  195.   if not Empty then Canvas.Lock;
  196.   try
  197.     inherited Draw(ACanvas, Rect);
  198.   finally
  199.     if not Empty then Canvas.Unlock;
  200.   end;
  201. end;
  202.  
  203. type
  204.   THack = class(TBitmap);
  205.  
  206. var
  207.   Hooked: Boolean = False;
  208.  
  209. procedure HookBitmap;
  210. var
  211.   Index: Integer;
  212. begin
  213.   if Hooked then Exit;
  214.   Index := FindVirtualMethodIndex(THack, @THack.Draw);
  215.   SetVirtualMethodAddress(TBitmap, Index, @THackBitmap.Draw);
  216.   Hooked := True;
  217. end;
  218.  
  219. {$ENDIF RX_D3}
  220.  
  221. { TRxImageControl }
  222.  
  223. constructor TRxImageControl.Create(AOwner: TComponent);
  224. begin
  225.   inherited Create(AOwner);
  226. {$IFDEF RX_D3}
  227.   InitializeCriticalSection(FLock);
  228. {$ENDIF}
  229.   ControlStyle := ControlStyle + [csClickEvents, csCaptureMouse, csOpaque,
  230.     {$IFDEF WIN32} csReplicatable, {$ENDIF} csDoubleClicks];
  231.   Height := 105;
  232.   Width := 105;
  233.   ParentColor := True;
  234. end;
  235.  
  236. destructor TRxImageControl.Destroy;
  237. begin
  238. {$IFDEF RX_D3}
  239.   DeleteCriticalSection(FLock);
  240. {$ENDIF}
  241.   inherited Destroy;
  242. end;
  243.  
  244. procedure TRxImageControl.Lock;
  245. begin
  246. {$IFDEF RX_D3}
  247.   EnterCriticalSection(FLock);
  248. {$ENDIF}
  249. end;
  250.  
  251. procedure TRxImageControl.Unlock;
  252. begin
  253. {$IFDEF RX_D3}
  254.   LeaveCriticalSection(FLock);
  255. {$ENDIF}
  256. end;
  257.  
  258. procedure TRxImageControl.PaintImage;
  259. var
  260.   Save: Boolean;
  261. begin
  262.   with Canvas do begin
  263.     Brush.Color := Color;
  264.     FillRect(Bounds(0, 0, ClientWidth, ClientHeight));
  265.   end;
  266.   Save := FDrawing;
  267.   FDrawing := True;
  268.   try
  269.     DoPaintImage;
  270.   finally
  271.     FDrawing := Save;
  272.   end;
  273. end;
  274.  
  275. procedure TRxImageControl.WMPaint(var Message: TWMPaint);
  276. var
  277.   DC, MemDC: HDC;
  278.   MemBitmap, OldBitmap: HBITMAP;
  279. begin
  280.   if FPaintBuffered then
  281.     inherited
  282.   else if Message.DC <> 0 then begin
  283. {$IFDEF RX_D3}
  284.     Canvas.Lock;
  285.     try
  286. {$ENDIF}
  287.       DC := Message.DC;
  288.       MemDC := GetDC(0);
  289.       MemBitmap := CreateCompatibleBitmap(MemDC, ClientWidth, ClientHeight);
  290.       ReleaseDC(0, MemDC);
  291.       MemDC := CreateCompatibleDC(0);
  292.       OldBitmap := SelectObject(MemDC, MemBitmap);
  293.       try
  294.         FPaintBuffered := True;
  295.         try
  296.           Message.DC := MemDC;
  297.           WMPaint(Message);
  298.           Message.DC := 0;
  299.         finally
  300.           FPaintBuffered := False;
  301.         end;
  302.         BitBlt(DC, 0, 0, ClientWidth, ClientHeight, MemDC, 0, 0, SRCCOPY);
  303.       finally
  304.         SelectObject(MemDC, OldBitmap);
  305.         DeleteDC(MemDC);
  306.         DeleteObject(MemBitmap);
  307.       end;
  308. {$IFDEF RX_D3}
  309.     finally
  310.       Canvas.Unlock;
  311.     end;
  312. {$ENDIF}
  313.   end;
  314. end;
  315.  
  316. procedure TRxImageControl.PaintDesignRect;
  317. begin
  318.   if csDesigning in ComponentState then
  319.     with Canvas do begin
  320.       Pen.Style := psDash;
  321.       Brush.Style := bsClear;
  322.       Rectangle(0, 0, Width, Height);
  323.     end;
  324. end;
  325.  
  326. procedure TRxImageControl.DoPaintControl;
  327. var
  328.   DC: HDC;
  329. begin
  330. {$IFDEF RX_D3}
  331.   if GetCurrentThreadID = MainThreadID then begin
  332.     Repaint;
  333.     Exit;
  334.   end;
  335. {$ENDIF}
  336.   DC := GetDC(Parent.Handle);
  337.   try
  338.     IntersectClipRect(DC, Left, Top, Left + Width, Top + Height);
  339.     MoveWindowOrg(DC, Left, Top);
  340.     Perform(WM_PAINT, DC, 0);
  341.   finally
  342.     ReleaseDC(Parent.Handle, DC);
  343.   end;
  344. end;
  345.  
  346. function TRxImageControl.DoPaletteChange: Boolean;
  347. var
  348.   ParentForm: TCustomForm;
  349.   Tmp: TGraphic;
  350. begin
  351.   Result := False;
  352.   Tmp := FGraphic;
  353.   if Visible and (not (csLoading in ComponentState)) and (Tmp <> nil)
  354.     {$IFDEF RX_D3} and (Tmp.PaletteModified) {$ENDIF} then
  355.   begin
  356.     if (GetPalette <> 0) then begin
  357.       ParentForm := GetParentForm(Self);
  358.       if Assigned(ParentForm) and ParentForm.Active and ParentForm.HandleAllocated then
  359.       begin
  360.         if FDrawing then
  361.           ParentForm.Perform(WM_QUERYNEWPALETTE, 0, 0)
  362.         else
  363.           PostMessage(ParentForm.Handle, WM_QUERYNEWPALETTE, 0, 0);
  364.         Result := True;
  365. {$IFDEF RX_D3}
  366.         Tmp.PaletteModified := False;
  367. {$ENDIF}
  368.       end;
  369.     end
  370. {$IFDEF RX_D3}
  371.     else begin
  372.       Tmp.PaletteModified := False;
  373.     end;
  374. {$ENDIF}
  375.   end;
  376. end;
  377.  
  378. procedure TRxImageControl.PictureChanged;
  379. begin
  380.   if not (csDestroying in ComponentState) then begin
  381.     AdjustSize;
  382.     if (FGraphic <> nil) then
  383.       if DoPaletteChange and FDrawing then Update;
  384.     if not FDrawing then Invalidate;
  385.   end;
  386. end;
  387.  
  388. { TAnimatedImage }
  389.  
  390. constructor TAnimatedImage.Create(AOwner: TComponent);
  391. begin
  392.   inherited Create(AOwner);
  393.   FTimer := TRxTimer.Create(Self);
  394.   with FTimer do begin
  395.     Enabled := False;
  396.     Interval := 100;
  397.   end;
  398.   AutoSize := True;
  399.   FGlyph := TBitmap.Create;
  400.   FGraphic := FGlyph;
  401.   FGlyph.OnChange := ImageChanged;
  402.   FNumGlyphs := 1;
  403.   FInactiveGlyph := -1;
  404.   FTransparentColor := clNone;
  405.   FOrientation := goHorizontal;
  406.   FStretch := True;
  407. end;
  408.  
  409. destructor TAnimatedImage.Destroy;
  410. begin
  411.   Destroying;
  412.   FOnFrameChanged := nil;
  413.   FOnStart := nil;
  414.   FOnStop := nil;
  415.   FGlyph.OnChange := nil;
  416.   Active := False;
  417.   FGlyph.Free;
  418.   inherited Destroy;
  419. end;
  420.  
  421. procedure TAnimatedImage.Loaded;
  422. begin
  423.   inherited Loaded;
  424.   ResetImageBounds;
  425.   UpdateInactive;
  426. end;
  427.  
  428. function TAnimatedImage.GetPalette: HPALETTE;
  429. begin
  430.   Result := 0;
  431.   if not FGlyph.Empty then Result := FGlyph.Palette;
  432. end;
  433.  
  434. procedure TAnimatedImage.ImageChanged(Sender: TObject);
  435. begin
  436.   Lock;
  437.   try
  438.     FTransparentColor := FGlyph.TransparentColor and not PaletteMask;
  439.   finally
  440.     Unlock;
  441.   end;
  442.   DefineBitmapSize;
  443.   PictureChanged;
  444. end;
  445.  
  446. procedure TAnimatedImage.UpdateInactive;
  447. begin
  448.   if (not Active) and (FInactiveGlyph >= 0) and
  449.     (FInactiveGlyph < FNumGlyphs) and (FGlyphNum <> FInactiveGlyph) then
  450.   begin
  451.     Lock;
  452.     try
  453.       FGlyphNum := FInactiveGlyph;
  454.     finally
  455.       Unlock;
  456.     end;
  457.   end;
  458. end;
  459.  
  460. function TAnimatedImage.TransparentStored: Boolean;
  461. begin
  462.   Result := (FGlyph.Empty and (FTransparentColor <> clNone)) or
  463.     ((FGlyph.TransparentColor and not PaletteMask) <>
  464.     FTransparentColor);
  465. end;
  466.  
  467. procedure TAnimatedImage.SetOpaque(Value: Boolean);
  468. begin
  469.   if Value <> FOpaque then begin
  470.     Lock;
  471.     try
  472.       FOpaque := Value;
  473.     finally
  474.       Unlock;
  475.     end;
  476.     PictureChanged;
  477.   end;
  478. end;
  479.  
  480. procedure TAnimatedImage.SetTransparentColor(Value: TColor);
  481. begin
  482.   if Value <> TransparentColor then begin
  483.     Lock;
  484.     try
  485.       FTransparentColor := Value;
  486.     finally
  487.       Unlock;
  488.     end;
  489.     PictureChanged;
  490.   end;
  491. end;
  492.  
  493. procedure TAnimatedImage.SetOrientation(Value: TGlyphOrientation);
  494. begin
  495.   if FOrientation <> Value then begin
  496.     Lock;
  497.     try
  498.       FOrientation := Value;
  499.     finally
  500.       Unlock;
  501.     end;
  502.     ImageChanged(FGlyph);
  503.   end;
  504. end;
  505.  
  506. procedure TAnimatedImage.SetGlyph(Value: TBitmap);
  507. begin
  508.   Lock;
  509.   try
  510.     FGlyph.Assign(Value);
  511.   finally
  512.     Unlock;
  513.   end;
  514. end;
  515.  
  516. procedure TAnimatedImage.SetStretch(Value: Boolean);
  517. begin
  518.   if Value <> FStretch then begin
  519.     Lock;
  520.     try
  521.       FStretch := Value;
  522.     finally
  523.       Unlock;
  524.     end;
  525.     PictureChanged;
  526.     if Active then Repaint;
  527.   end;
  528. end;
  529.  
  530. procedure TAnimatedImage.SetCenter(Value: Boolean);
  531. begin
  532.   if Value <> FCenter then begin
  533.     Lock;
  534.     try
  535.       FCenter := Value;
  536.     finally
  537.       Unlock;
  538.     end;
  539.     PictureChanged;
  540.     if Active then Repaint;
  541.   end;
  542. end;
  543.  
  544. procedure TAnimatedImage.SetGlyphNum(Value: Integer);
  545. begin
  546.   if Value <> FGlyphNum then begin
  547.     if (Value < FNumGlyphs) and (Value >= 0) then begin
  548.       Lock;
  549.       try
  550.         FGlyphNum := Value;
  551.       finally
  552.         Unlock;
  553.       end;
  554.       UpdateInactive;
  555.       FrameChanged;
  556.       PictureChanged;
  557.     end;
  558.   end;
  559. end;
  560.  
  561. procedure TAnimatedImage.SetInactiveGlyph(Value: Integer);
  562. begin
  563.   if Value < 0 then Value := -1;
  564.   if Value <> FInactiveGlyph then begin
  565.     if (Value < FNumGlyphs) or (csLoading in ComponentState) then begin
  566.       Lock;
  567.       try
  568.         FInactiveGlyph := Value;
  569.         UpdateInactive;
  570.       finally
  571.         Unlock;
  572.       end;
  573.       FrameChanged;
  574.       PictureChanged;
  575.     end;
  576.   end;
  577. end;
  578.  
  579. procedure TAnimatedImage.SetNumGlyphs(Value: Integer);
  580. begin
  581.   Lock;
  582.   try
  583.     FNumGlyphs := Value;
  584.     if FInactiveGlyph >= FNumGlyphs then begin
  585.       FInactiveGlyph := -1;
  586.       FGlyphNum := 0;
  587.     end
  588.     else UpdateInactive;
  589.     ResetImageBounds;
  590.   finally
  591.     Unlock;
  592.   end;
  593.   FrameChanged;
  594.   PictureChanged;
  595. end;
  596.  
  597. procedure TAnimatedImage.DefineBitmapSize;
  598. begin
  599.   Lock;
  600.   try
  601.     FNumGlyphs := 1;
  602.     FGlyphNum := 0;
  603.     FImageWidth := 0;
  604.     FImageHeight := 0;
  605.     if (FOrientation = goHorizontal) and (FGlyph.Height > 0) and
  606.       (FGlyph.Width mod FGlyph.Height = 0) then
  607.       FNumGlyphs := FGlyph.Width div FGlyph.Height
  608.     else if (FOrientation = goVertical) and (FGlyph.Width > 0) and
  609.       (FGlyph.Height mod FGlyph.Width = 0) then
  610.       FNumGlyphs := FGlyph.Height div FGlyph.Width;
  611.     ResetImageBounds;
  612.   finally
  613.     Unlock;
  614.   end;
  615. end;
  616.  
  617. procedure TAnimatedImage.ResetImageBounds;
  618. begin
  619.   if FNumGlyphs < 1 then FNumGlyphs := 1;
  620.   if FOrientation = goHorizontal then begin
  621.     FImageHeight := FGlyph.Height;
  622.     FImageWidth := FGlyph.Width div FNumGlyphs;
  623.   end
  624.   else {if Orientation = goVertical then} begin
  625.     FImageWidth := FGlyph.Width;
  626.     FImageHeight := FGlyph.Height div FNumGlyphs;
  627.   end;
  628. end;
  629.  
  630. procedure TAnimatedImage.AdjustSize;
  631. begin
  632.   if not (csReading in ComponentState) then begin
  633.     if AutoSize and (FImageWidth > 0) and (FImageHeight > 0) then
  634.       SetBounds(Left, Top, FImageWidth, FImageHeight);
  635.   end;
  636. end;
  637.  
  638. procedure TAnimatedImage.DoPaintImage;
  639. var
  640.   BmpIndex: Integer;
  641.   SrcRect, DstRect: TRect;
  642.   {Origin: TPoint;}
  643. begin
  644.   if (not Active) and (FInactiveGlyph >= 0) and
  645.     (FInactiveGlyph < FNumGlyphs) then BmpIndex := FInactiveGlyph
  646.   else BmpIndex := FGlyphNum;
  647.   { copy image from parent and back-level controls }
  648.   if not FOpaque then CopyParentImage(Self, Canvas);
  649.   if (FImageWidth > 0) and (FImageHeight > 0) then begin
  650.     if Orientation = goHorizontal then
  651.       SrcRect := Bounds(BmpIndex * FImageWidth, 0, FImageWidth, FImageHeight)
  652.     else {if Orientation = goVertical then}
  653.       SrcRect := Bounds(0, BmpIndex * FImageHeight, FImageWidth, FImageHeight);
  654.     if Stretch then DstRect := ClientRect
  655.     else if Center then
  656.       DstRect := Bounds((ClientWidth - FImageWidth) div 2,
  657.         (ClientHeight - FImageHeight) div 2, FImageWidth, FImageHeight)
  658.     else
  659.       DstRect := Rect(0, 0, FImageWidth, FImageHeight);
  660.     with DstRect do
  661.       StretchBitmapRectTransparent(Canvas, Left, Top, Right - Left,
  662.         Bottom - Top, SrcRect, FGlyph, FTransparentColor);
  663.   end;
  664. end;
  665.  
  666. procedure TAnimatedImage.Paint;
  667. begin
  668.   PaintImage;
  669.   if (not Opaque) or FGlyph.Empty then
  670.     PaintDesignRect;
  671. end;
  672.  
  673. procedure TAnimatedImage.TimerExpired(Sender: TObject);
  674. begin
  675. {$IFDEF RX_D3}
  676.   if csPaintCopy in ControlState then Exit;
  677. {$ENDIF}
  678.   if Visible and (FNumGlyphs > 1) and (Parent <> nil) and
  679.     Parent.HandleAllocated then
  680.   begin
  681.     Lock;
  682.     try
  683.       if FGlyphNum < FNumGlyphs - 1 then Inc(FGlyphNum)
  684.       else FGlyphNum := 0;
  685.       if (FGlyphNum = FInactiveGlyph) and (FNumGlyphs > 1) then begin
  686.         if FGlyphNum < FNumGlyphs - 1 then Inc(FGlyphNum)
  687.         else FGlyphNum := 0;
  688.       end;
  689. {$IFDEF RX_D3}
  690.       Canvas.Lock;
  691.       try
  692.         FTimerRepaint := True;
  693.         if AsyncDrawing and Assigned(FOnFrameChanged) then
  694.           FTimer.Synchronize(FrameChanged)
  695.         else FrameChanged;
  696.         DoPaintControl;
  697.       finally
  698.         FTimerRepaint := False;
  699.         Canvas.Unlock;
  700.       end;
  701. {$ELSE}
  702.       FTimerRepaint := True;
  703.       try
  704.         FrameChanged;
  705.         Repaint;
  706.       finally
  707.         FTimerRepaint := False;
  708.       end;
  709. {$ENDIF}
  710.     finally
  711.       Unlock;
  712.     end;
  713.   end;
  714. end;
  715.  
  716. procedure TAnimatedImage.FrameChanged;
  717. begin
  718.   if Assigned(FOnFrameChanged) then FOnFrameChanged(Self);
  719. end;
  720.  
  721. procedure TAnimatedImage.Stop;
  722. begin
  723.   if not (csReading in ComponentState) then
  724.     if Assigned(FOnStop) then FOnStop(Self);
  725. end;
  726.  
  727. procedure TAnimatedImage.Start;
  728. begin
  729.   if not (csReading in ComponentState) then
  730.     if Assigned(FOnStart) then FOnStart(Self);
  731. end;
  732.  
  733. {$IFNDEF RX_D4}
  734. procedure TAnimatedImage.SetAutoSize(Value: Boolean);
  735. begin
  736.   if Value <> FAutoSize then begin
  737.     FAutoSize := Value;
  738.     PictureChanged;
  739.   end;
  740. end;
  741. {$ENDIF}
  742.  
  743. {$IFDEF RX_D4}
  744. function TAnimatedImage.CanAutoSize(var NewWidth, NewHeight: Integer): Boolean;
  745. begin
  746.   Result := True;
  747.   if not (csDesigning in ComponentState) and (FImageWidth > 0) and
  748.     (FImageHeight > 0) then
  749.   begin
  750.     if Align in [alNone, alLeft, alRight] then
  751.       NewWidth := FImageWidth;
  752.     if Align in [alNone, alTop, alBottom] then
  753.       NewHeight := FImageHeight;
  754.   end;
  755. end;
  756. {$ENDIF}
  757.  
  758. procedure TAnimatedImage.SetInterval(Value: Cardinal);
  759. begin
  760.   FTimer.Interval := Value;
  761. end;
  762.  
  763. function TAnimatedImage.GetInterval: Cardinal;
  764. begin
  765.   Result := FTimer.Interval;
  766. end;
  767.  
  768. procedure TAnimatedImage.SetActive(Value: Boolean);
  769. begin
  770.   if FActive <> Value then begin
  771.     if Value then begin
  772.       FTimer.OnTimer := TimerExpired;
  773.       FTimer.Enabled := True;
  774.       FActive := FTimer.Enabled;
  775.       Start;
  776.     end
  777.     else begin
  778.       FTimer.Enabled := False;
  779.       FTimer.OnTimer := nil;
  780.       FActive := False;
  781.       UpdateInactive;
  782.       FrameChanged;
  783.       Stop;
  784.       PictureChanged;
  785.     end;
  786.   end;
  787. end;
  788.  
  789. {$IFDEF RX_D3}
  790. procedure TAnimatedImage.SetAsyncDrawing(Value: Boolean);
  791. begin
  792.   if FAsyncDrawing <> Value then begin
  793.     Lock;
  794.     try
  795.       if Value then HookBitmap;
  796.       if Assigned(FTimer) then FTimer.SyncEvent := not Value;
  797.       FAsyncDrawing := Value;
  798.     finally
  799.       Unlock;
  800.     end;
  801.   end;
  802. end;
  803. {$ENDIF}
  804.  
  805. procedure TAnimatedImage.WMSize(var Message: TWMSize);
  806. begin
  807.   inherited;
  808. {$IFNDEF RX_D4}
  809.   AdjustSize;
  810. {$ENDIF}
  811. end;
  812.  
  813. end.